package org.carabiner.infinitest.depgraph;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;

import org.carabiner.infinitest.InfinitestUtils;

/**
 * The <code>JavaClassBuilder</code> builds <code>JavaClass</code> instances from .class, .jar,
 * .war, or .zip files.
 * 
 * @author <b>Mike Clark</b>
 * @author Clarkware Consulting, Inc.
 */
class JavaClassBuilder
{
  private AbstractParser parser;
  private List<File> classpathDirs;

  public JavaClassBuilder(List<File> classDirList)
  {
    classpathDirs = classDirList;
    parser = new ClassFileParser();
  }

  /**
   * Builds the <code>JavaClass</code> instances from the specified file.
   * 
   * @param file
   *          Class or Jar file.
   * @return Collection of <code>JavaClass</code> instances.
   */
  public Collection<JavaClass> buildClasses(File file) throws IOException
  {
    if (!file.exists())
      throw new IllegalArgumentException(file + " does not exist");
    FileInputStream fis = null;
    try
    {
      fis = new FileInputStream(file);
      JavaClass parsedClass = parser.parse(fis);
      Collection<JavaClass> javaClasses = new ArrayList<JavaClass>();
      javaClasses.add(parsedClass);
      return javaClasses;
    }
    finally
    {
      if (fis != null)
      {
        fis.close();
      }
    }
  }
  
  public boolean isProjectClass(String classname)
  {
    for(File classDir : classpathDirs)
    {
      if (!classDir.isDirectory())
        throw new IllegalStateException(classDir + " is not a directory!");
      if (new File(classDir + getResourceName(classname)).exists())
        return true;
    }
    return false;
  }

  public JavaClass createClass(String classname) throws IOException
  {
    if (!isProjectClass(classname))
      return null;
    String resourceName = getResourceName(classname);
    InputStream stream = getInputStream(resourceName);
    JavaClass clazz = parser.parse(stream);
    return clazz;
  }

  static String getResourceName(String classname)
  {
    classname = "/" + classname.replace('.', '/') + ".class";
    return classname;
  }

  private InputStream getInputStream(String resourceName)
  {
    InputStream stream = getClass().getResourceAsStream(resourceName);
    if (stream == null)
    {
      String cleanClasspath = InfinitestUtils.getCleanClasspath(System.getProperty("java.class.path"));
      throw new IllegalArgumentException("Class not found: " + resourceName + " in classpath " + cleanClasspath);

    }
    return stream;
  }

}
